//***********************************************************
//*
//* File:           TournamentResults.java
//* Author:         Abhinav Kamra
//* Contact:        kamra@cs.columbia.edu
//* Update:         9.14.2003
//*
//* Description:    Tournament results analysis class
//*                 responsible for computing statistics
//*                 and generating a table model.
//*
//***********************************************************

package ui;

import java.util.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.text.NumberFormat;

public final class TournamentResults implements IFCTournamentResults {

    ArrayList       _listeners;
    Class           _cellclass;
    IFCGameRecord[] _games;
    String[][]      _table;
    NumberFormat    _nf;
    PlayerEntry[]   _entries;
    static final String _CNAME      = "Tournament Results";
    static final int _CNUM_GAMES    = 0;
    static final int _CAVG_RANK     = 1;
    static final int _CRANK1        = 2;
    static final int _CRANK2        = 3;
    static final int _CRANK3        = 4;
    static final int _CRANK4        = 5;
    static final int _CRANK5        = 6;
    static final int _CRANK6        = 7;
    static final int _CRANK7        = 8;
    static final int _CRANK8        = 9;
    static final int _CRANK9        = 10;
    static final int _CRANK10       = 11;
    static final int[] _CVALUE_COLUMNS = { _CNUM_GAMES, _CAVG_RANK, _CRANK1, _CRANK2, _CRANK3, _CRANK4, _CRANK5, _CRANK6, _CRANK7, _CRANK8, _CRANK9, _CRANK10 };
    static final String[] _CNAMES = { "Player", "NumGames", "AvgRank", "Rank1", "Rank2", "Rank3", "Rank4", "Rank5", "Rank6", "Rank7", "Rank8", "Rank9", "Rank10" };

    public TournamentResults(IFCGameRecord[] __games) throws Exception {
        HashMap hash;
        Class[] players;
        PlayerEntry pe;
        double[] scores;
        int _MAXI;
        int _MAXJ;

        _listeners = new ArrayList();
        _cellclass = new String().getClass();
        _games = __games;

        hash = new HashMap();
        _MAXI = _games.length;
        _MAXJ = 0;
        for (int i=0; i < _MAXI; i++) {
            players = _games[i].players();
            scores = _games[i].scores();
            _MAXJ = players.length;

            for (int j=0; j < _MAXJ; j++) {
                pe = (PlayerEntry) hash.get(players[j]);
                if (pe == null) {
                    pe = new PlayerEntry(players[j]);;
                    hash.put(players[j], pe);
                }
                pe.set(_CNUM_GAMES, pe.get(_CNUM_GAMES) + 1);
		int rank = (int)scores[j];
		switch(rank)
		{
		case 1:
			pe.set(_CRANK1, pe.get(_CRANK1) + 1);
			break;
		case 2:
			pe.set(_CRANK2, pe.get(_CRANK2) + 1);
			break;
		case 3:
			pe.set(_CRANK3, pe.get(_CRANK3) + 1);
			break;
		case 4:
			pe.set(_CRANK4, pe.get(_CRANK4) + 1);
			break;
		case 5:
			pe.set(_CRANK5, pe.get(_CRANK5) + 1);
			break;
		case 6:
			pe.set(_CRANK6, pe.get(_CRANK6) + 1);
			break;
		case 7:
			pe.set(_CRANK7, pe.get(_CRANK7) + 1);
			break;
		case 8:
			pe.set(_CRANK8, pe.get(_CRANK8) + 1);
			break;
		case 9:
			pe.set(_CRANK9, pe.get(_CRANK9) + 1);
			break;
		case 10:
			pe.set(_CRANK10, pe.get(_CRANK10) + 1);
			break;
		default:
			throw new Exception("Error:  Player Class Rank Not Found: " + players[j]);
		}
            }
        }
        _entries = (PlayerEntry[]) hash.values().toArray(new PlayerEntry[0]);
        _MAXI = _entries.length;
        for (int i=0; i < _MAXI; i++) {
            _entries[i].setAvg(_CAVG_RANK, _CRANK1, _CRANK1 + _MAXJ - 1);
        }
        _nf = NumberFormat.getInstance();
        _nf.setMinimumFractionDigits(3);
        _nf.setMaximumFractionDigits(3);
        _nf.setMinimumIntegerDigits(1);
        Arrays.sort(_entries, new PlayerEntrySorter(_CAVG_RANK));
        generateTable();
    }

    public void generateTable() throws Exception {
        int _MAXI = _entries.length;
        int _MAXJ = _CVALUE_COLUMNS.length;
        String[] toks;

        _table = new String[_MAXI][_CNAMES.length];
        _MAXJ = _CVALUE_COLUMNS.length;
        for (int i=0; i < _MAXI; i++) {
            toks = Util.split(".", _entries[i].toString());
            _table[i][0] = toks[toks.length-1];
            for (int j=0; j < _MAXJ; j++) {
                _table[i][j+1] = _nf.format(_entries[i].get(j));
            }
        }
    }
    
    public String name() throws Exception {
        return _CNAME;
    }

	public void Print() throws Exception
	{
		int x = getRowCount();
		int y = getColumnCount();
		
		System.out.println("[" + _games[0].numHiddenCards() + " HiddenCards, " + (_games[0].players()).length + " Players, k = " + _games[0].cardsperplayer() + "]");
		for(int i=0;i < y;i++)
			System.out.print(_CNAMES[i] + "\t");
		System.out.println();
		for(int i=0;i < x;i++)
		{
//			System.out.print(_names[i] + "\t");
			for(int j=0;j < y;j++)
			{
				System.out.print((String)getValueAt(i, j) + "\t");
			}
			System.out.println();
		}
		System.out.println();
	}

    public void addTableModelListener(TableModelListener __listener) {
        if (!_listeners.contains(__listener)) {
            _listeners.add(__listener);
        }
    }

    public void removeTableModelListener(TableModelListener __listener) {
        _listeners.remove(__listener);
    }

    public Class getColumnClass(int __col) {
        return _cellclass;
    }

    public int getColumnCount() {
        return _CVALUE_COLUMNS.length + 1;
    }

    public String getColumnName(int __col) {
        return _CNAMES[__col];
    }

    public int getRowCount() {
        if (_table == null) {
            return 0;
        }
        return _table.length;
    }

    public Object getValueAt(int __row, int __col) {
        return _table[__row][__col];
    }

    public boolean isCellEditable(int __row, int __col) {
        return false;
    }

    public void setValueAt(Object __obj, int __row, int __col)
    { }
    
    public void columnAdded(TableColumnModelEvent __event) 
    { }
    
    public void columnMarginChanged(ChangeEvent __event)
    { }

    public void columnMoved(TableColumnModelEvent __event)
    { }
    
    public void columnRemoved(TableColumnModelEvent __event)
    { }
    
    public void columnSelectionChanged(ListSelectionEvent __event) {
        try {
            int index = __event.getFirstIndex();
        
            if (index == 0) {
                Arrays.sort(_entries);
                generateTable();
                return;
            }
            Arrays.sort(_entries, new PlayerEntrySorter(index-1));
            generateTable();
        } catch (Exception EXC) {
            System.out.println(EXC.getMessage());
            EXC.printStackTrace();
        }
    }

    private class PlayerEntry implements Comparable {
        Class _player;
        String _name;
        double[] _values;

        public PlayerEntry(Class __player) throws Exception {
            _player = __player;
            _name = _player.toString();
            _values = new double[_CVALUE_COLUMNS.length];
        }
        
        public void set(int __pos, double __val) throws Exception {
            _values[__pos] = __val;
        }

        public void setAvg(int __pos, int __start, int __end) throws Exception {
		double avg = 0;
		double sum = 0;
		for(int i=__start;i <= __end;i++)
		{
			avg += (i - __start + 1) * _values[i];
			sum += _values[i];
		}
		_values[__pos] = avg/sum;
        }

        public double get(int __pos) throws Exception {
            return _values[__pos];
        }
        
        public int compareTo(Object __obj) {
            return toString().compareTo(((PlayerEntry) __obj).toString());
        }

        public boolean equals(Object __obj) {
            if (!(__obj instanceof PlayerEntry)) {
                return false;
            }
            return ((PlayerEntry) __obj).equals(this);
        }

        public String toString() {
            return _name;
        }
    }
    
    private class ClassScorePair implements Comparable {
    
        Class _class;
        double _score;
        
        public ClassScorePair(Class __class, double __score) throws Exception {
            _class = __class;
            _score = __score;
        }
        
        public int compareTo(Object __obj) {
            try {
                double score = ((ClassScorePair) __obj)._score;

                return (_score > score ? -1 : (_score < score ? 1 : 0));
            } catch (Exception EXC) {
                System.out.println(EXC.getMessage());
                EXC.printStackTrace();
                return 0;
            }
        }

        public Class playerClass() throws Exception {
            return _class;
        }

        public double score() throws Exception {
            return score();
        }
    }
    
    private class PlayerEntrySorter implements Comparator {
        
        int _sortindex;
    
        public PlayerEntrySorter(int __sortindex) {
            _sortindex = __sortindex;
        }

        public int compare(Object __obj1, Object __obj2) {
            try {
                double val1 = ((PlayerEntry) __obj1).get(_sortindex);
                double val2 = ((PlayerEntry) __obj2).get(_sortindex);

                return (val1 < val2 ? -1 : (val1 > val2 ? 1 : 0));
            } catch (Exception EXC) {
                System.out.println(EXC.getMessage());
                EXC.printStackTrace();
                return 0;
            }
         }
    }
}
